﻿using System;
using System.Data;
using System.Data.Common;
using System.Linq;

namespace SimpleORM
{
    public class DbCParameter : DParameter
    {
        #region Properties

        public DbParameter Instance { get; set; }

        public override string Name
        {
            get { return base.Name; }
            set
            {
                base.Name = value;
                if (Instance == null)
                    base.ParameterName = value;
                else
                    Instance.ParameterName =
                        string.Format("@{0}{1}", value,
                        rd.Next(int.MaxValue).ToString("X"));
            }
        }

        public override string ParameterName
        {
            get { return Instance == null ? base.ParameterName : Instance.ParameterName; }
            set
            {
                if (Instance == null)
                    base.ParameterName = value;
                else
                    Instance.ParameterName = string.Format("@{0}", value);
            }
        }

        public override object Value
        {
            get { return Instance == null ? base.Value : Instance.Value; }
            set
            {
                if (Instance == null)
                    base.Value = value;
                else
                    Instance.Value = value;
            }
        }

        public override object Type
        {
            get { return Instance == null ? base.Type : Instance.DbType; }
            set
            {
                if (Instance == null)
                    base.Type = value;
                else
                    Instance.DbType = (value is DbType) ? (DbType)value : Instance.DbType;
            }
        }

        public override int Size
        {
            get { return Instance == null ? base.Size : Instance.Size; }
            set
            {
                if (Instance == null)
                    base.Size = value;
                else
                    Instance.Size = value;
            }
        }

        public override ParameterDirection Direction
        {
            get { return Instance == null ? base.Direction : Instance.Direction; }
            set
            {
                if (Instance == null)
                    base.Direction = value;
                else
                    Instance.Direction = value;
            }
        }

        #endregion

        #region Field

        private static Random rd = new Random((int)DateTime.Now.Ticks);

        #endregion

        #region Ctor

        public DbCParameter()
        {
        }

        public DbCParameter(DbParameter parameter)
            : this()
        {
            Instance = parameter;
        }

        #endregion

        #region Methods

        #region Methods - Public

        public override object Clone()
        {
            if (Instance == null)
                return base.Clone();

            DbCParameter newParameter = Activator.CreateInstance(this.GetType(),
                         new object[] { Activator.CreateInstance(Instance.GetType()) }) as DbCParameter;

            newParameter.CopyPropertiesFromExcept(this, new string[] { "Instance" });

            return newParameter;
        }

        public override void Dispose()
        {
            base.Dispose();

            Instance = null;
        }

        #endregion

        #region Methods - Override

        protected override string OnGetValueString()
        {
            if (Instance == null || Value == null)
                return base.OnGetValueString();

            string txt = string.Empty;

            switch (Instance.DbType)
            {
                case DbType.AnsiString:
                case DbType.AnsiStringFixedLength:
                case DbType.String:
                case DbType.StringFixedLength:
                case DbType.Xml:
                    txt = Format((string)Value);
                    break;
                case DbType.Time:
                case DbType.Date:
                case DbType.DateTime:
                case DbType.DateTime2:
                //txt = string.Format("'{0}'", ((DateTime)Value).ToString("yyyy/MM/dd hh:mm:ss.fff"));
                //break;
                case DbType.DateTimeOffset:
                case DbType.Guid:
                    txt = string.Format("'{0}'", Value);
                    break;
                case DbType.Boolean:
                    txt = Convert.ToInt32(Value).ToString();
                    break;
                case DbType.Byte:
                    txt = ((byte)Value).ToString();
                    break;
                case DbType.SByte:
                    txt = ((sbyte)Value).ToString();
                    break;
                case DbType.Int16:
                    txt = ((short)Value).ToString();
                    break;
                case DbType.Int32:
                    txt = ((int)Value).ToString();
                    break;
                case DbType.Int64:
                    txt = ((long)Value).ToString();
                    break;
                case DbType.UInt16:
                    txt = ((ushort)Value).ToString();
                    break;
                case DbType.UInt32:
                    txt = ((uint)Value).ToString();
                    break;
                case DbType.UInt64:
                    txt = ((ulong)Value).ToString();
                    break;
                case DbType.Single:
                case DbType.Decimal:
                case DbType.Double:
                    txt = Value.ToString();
                    break;
                case DbType.Binary:
                    txt = string.Format("0x{0}", ((byte[])Value).ToHexString());
                    break;
                case DbType.Object:
                    txt = string.Format("0x{0}", Serializer.SerializeToBytes(Value).ToHexString());
                    break;
                case DbType.Currency:
                case DbType.VarNumeric:
                    txt = Value.ToString();
                    break;
                default:
                    txt = Value.ToString();
                    break;
            }

            return txt;
        }

        #endregion

        #region Methods - Static

        public static string Correct(string value)
        {
            if (value.Contains('\''))
                return value.Replace("\'", "\'\'");

            return value;
        }

        public static string Format(string value)
        {
            return string.Format("'{0}'", Correct(value));
        }

        #endregion

        #endregion
    }
}
